package v1

import (
	"errors"
	"io/ioutil"
	"net/http"
	"strconv"
	"zhejianglab/gin-apiserver/model"
	"zhejianglab/gin-apiserver/model/request"

	"github.com/astaxie/beego/validation"
	"github.com/gin-gonic/gin"
)

// AddNewDataset create new Dataset
// @Produce  json
// @Tags Dataset
// @Param AddNewDataset body request.DatasetInfo true "request.DatasetInfo"
// @Success 201 {object} gin.H "{"code":201,"msg":"AddNewDataset successfully"}"
// @Failure 409 {object} gin.H "{"code":500,"msg":"AddNewDataset: Dataset name is exist"}"
// @Failure 500 {object} gin.H "{"code":500,"msg":"AddNewDataset: Dataset name is invalid"}"
// @Router /api/v1/dataset/new [post]
func AddNewDataset(c *gin.Context) {
	var err error

	var Dataset request.DatasetInfo
	err = c.ShouldBindJSON(&Dataset)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": err.Error()})
		return
	}
	datasetInfo := model.DatasetInfo{
		Name:     Dataset.Name,
		FilePath: Dataset.FilePath,
		UserID:   Dataset.UserID,
		Type:     Dataset.Type,
	}
	valid := validation.Validation{}

	// 校验数据集名的有效性
	valid.Required(Dataset.Name, "name").Message("数据集名称不能为空")
	if valid.HasErrors() {
		err = errors.New("AddNewDataset: Dataset name is invalid")
		c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": err.Error()})
		return
	}

	if model.ExistDatasetByName(Dataset.Name) {
		err = errors.New("UpdateDataset: Dataset name is exist")
		c.JSON(http.StatusConflict, gin.H{"status": http.StatusConflict, "message": err.Error()})
		return
	}

	data, err := model.AddNewDataset(&datasetInfo)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": err.Error()})
		return
	}
	dataset, ok := data.(*model.DatasetInfo)
	if !ok {
		c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": "AddNewJob failed!"})
		return
	}
	c.JSON(http.StatusCreated, gin.H{"status": http.StatusCreated, "message": "AddNewDataset successfully!", "data": dataset.ID})
}

// GetDataset get Dataset info from db
// @Produce  json
// @Tags Dataset
// @Param id path int true "ID"
// @Success 200 {object} gin.H "{"code":200,"msg":"GetDataset successfully"}"
// @Failure 500 {object} gin.H "{"code":500,"msg":"GetDataset failed!"}"
// @Router /api/v1/dataset [get]
func GetDataset(c *gin.Context) {
	id := c.Query("id")
	DatasetType := c.Query("type")
	if id != "" {
		data, err := model.GetDataset(id)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": err.Error()})
			return
		}
		c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "message": "GetDataset successfully!", "data": data})
	} else if DatasetType != "" {
		data, err := model.GetDatasetByType(DatasetType)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": err.Error()})
			return
		}
		c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "message": "GetDataset successfully!", "data": data})
	} else {
		data, err := model.GetAllDatasets()
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": err.Error()})
			return
		}
		c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "message": "GetDataset successfully!", "data": data})
	}

}

// GetDataset get Dataset images info from db
// @Produce  json
// @Tags Dataset
// @Param id path int true "ID"
// @Success 200 {object} gin.H "{"code":200,"msg":"GetDataset successfully"}"
// @Failure 500 {object} gin.H "{"code":500,"msg":"GetDataset failed!"}"
// @Router /api/v1/dataset/images/{id} [get]
func GetDatasetImages(c *gin.Context) {
	id := c.Param("id")

	if id != "" {
		data, err := model.GetDataset(id)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": err.Error()})
			return
		}
		if data.FilePath == "" {
			c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": "dataset path is empty"})
			return
		}
		var result request.DatasetImage
		result.DatasetId = id
		datasetImagePath := data.FilePath + "/query"
		files, err := ioutil.ReadDir(datasetImagePath)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": err.Error()})
			return
		}

		for _, f := range files {
			image := request.Image{ImagePath: datasetImagePath + "/" + f.Name()}
			result.Image = append(result.Image, image)
		}

		c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "message": "GetDataset images successfully!", "data": result})
	} else {
		data, err := model.GetAllDatasets()
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": err.Error()})
			return
		}
		c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "message": "GetDataset successfully!", "data": data})
	}

}

// UpdateDataset update new Dataset
// @Produce  json
// @Tags Dataset
// @Param DatasetInfo body request.DatasetInfo true "request.DatasetInfo"
// @Success 201 {object} gin.H "{"code":201,"msg":"UpdateDataset successfully"}"
// @Failure 409 {object} gin.H "{"code":500,"msg":"UpdateDataset: Dataset name is exist"}"
// @Failure 500 {object} gin.H "{"code":500,"msg":"UpdateDataset: Dataset name is invalid"}"
// @Router /api/v1/dataset/{id} [put]
func UpdateDataset(c *gin.Context) {
	var err error
	data := make(map[string]interface{})
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": err.Error()})
		return
	}
	if !model.ExistDatasetByID(id) {
		c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": "Dataset id is not exists failed!"})
		return
	}

	var Dataset request.DatasetInfo

	err = c.ShouldBindJSON(&Dataset)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": "UpdateDataset failed!" + err.Error()})
		return
	}

	if Dataset.Name != "" {
		if model.ExistDatasetByName(Dataset.Name) {
			err = errors.New("UpdateDataset: Dataset name is exist")
			c.JSON(http.StatusConflict, gin.H{"status": http.StatusConflict, "message": err.Error()})
			return
		}
		data["name"] = Dataset.Name
	}

	if Dataset.UserID != 0 {
		data["user_id"] = Dataset.UserID
	}

	if Dataset.FilePath != "" {
		data["file_path"] = Dataset.FilePath
	}

	if Dataset.Type != 0 {
		data["type"] = Dataset.Type
	}

	model.UpdateDataset(id, data)
	c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "message": "UpdateDataset successfully!", "data": data})
	return

}

// DeleteDataset delete case info from db
// @Produce  json
// @Tags Dataset
// @Param id path int true "ID"
// @Success 200 {object} gin.H "{"code":200,"msg":"DeleteDataset successfully"}"
// @Failure 500 {object} gin.H "{"code":500,"msg":"DeleteDataset failed!"}"
// @Failure 500 {object} gin.H "{"code":500,"msg":"id is invalid!"}"
// @Router /api/v1/dataset/{id} [delete]
func DeleteDataset(c *gin.Context) {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": err.Error()})
		return
	}

	valid := validation.Validation{}
	valid.Min(id, 1, "id").Message("ID必须大于0")

	if !valid.HasErrors() {
		if model.ExistDatasetByID(id) {
			model.DeleteDataset(id)
			c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "message": "DeleteDataset successfully!"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": "DeleteDataset failed!"})
			return
		}
	} else {
		c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": "id is invalid!"})
		return
	}
}
